#include "LogicalDevice.h"

mini_engine::LogicalDevice *mini_engine::LogicalDevice::m_logicalDevice = nullptr;
VkDevice mini_engine::LogicalDevice::logicalDevice;
VkQueue mini_engine::LogicalDevice::graphicsQueue;
VkQueue mini_engine::LogicalDevice::presentQueue;

mini_engine::LogicalDevice::LogicalDevice()
{
}

void mini_engine::LogicalDevice::createLogicalDevice()
{
    cout << "CreateLogicalDevice" << endl;
    QueueFamilyIndices indices = QueueFamilies::getQueueFamilies()->findQueueFamilyIndices(PhysicalDevice::physicalDevice);

    std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
    std::set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()};

    float queuePriority = 1.0f;
    for (uint32_t queueFamily : uniqueQueueFamilies)
    {
        VkDeviceQueueCreateInfo queueCreateInfo{};
        queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
        queueCreateInfo.queueFamilyIndex = queueFamily;
        queueCreateInfo.queueCount = 1;
        queueCreateInfo.pQueuePriorities = &queuePriority;
        queueCreateInfos.push_back(queueCreateInfo);
    }

    VkPhysicalDeviceFeatures deviceFeatures{};

    VkDeviceCreateInfo createInfo{};
    createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;

    createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
    createInfo.pQueueCreateInfos = queueCreateInfos.data();

    createInfo.pEnabledFeatures = &deviceFeatures;

    createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
    createInfo.ppEnabledExtensionNames = deviceExtensions.data();

    createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
    createInfo.ppEnabledLayerNames = validationLayers.data();

    if (vkCreateDevice(PhysicalDevice::physicalDevice, &createInfo, nullptr, &LogicalDevice::logicalDevice) != VK_SUCCESS)
    {
        throw std::runtime_error("failed to create logical device!");
    }

    vkGetDeviceQueue(LogicalDevice::logicalDevice, indices.graphicsFamily.value(), 0, &graphicsQueue);
    vkGetDeviceQueue(LogicalDevice::logicalDevice, indices.presentFamily.value(), 0, &presentQueue);
}

mini_engine::LogicalDevice *mini_engine::LogicalDevice::getLogicalDevice()
{
    if (m_logicalDevice == nullptr)
    {
        m_logicalDevice = new LogicalDevice();
        static LogicalDeviceDestruction logicalDeviceDestruction;
    }
    return m_logicalDevice;
}

mini_engine::LogicalDevice::~LogicalDevice()
{
}

mini_engine::LogicalDevice::LogicalDeviceDestruction::~LogicalDeviceDestruction()
{
    if (m_logicalDevice != nullptr)
    {
        delete m_logicalDevice;
        m_logicalDevice = nullptr;
    }
}
